//
// Created by YE on 2024/2/16.
//

#ifndef MATINTERPRETER_INSTRUCTION_H
#define MATINTERPRETER_INSTRUCTION_H

#include "../common/ych_object.h"

typedef Uint Instruction;
/*code
+--------+---------+---------+--------+--------+--------+
|  iKABC |    C:9  |   B:9   |   A:5  |   k:2  |Opcode:7|
+--------+---------+---------+--------+--------+--------+
|  iKABx |   Bx:18(unsigned) |   A:5  |   k:2  |Opcode:7|
+--------+---------+---------+--------+--------+--------+
*/
#define R0 0
#define R1 1
#define R2 2
#define R3 3
#define R4 4
#define R5 5
#define R6 6
#define R7 7

#define K_NULL 0

#define LOAD_CONST_INT 0
#define LOAD_CONST_FLOAT 1
#define LOAD_CONST_BOOL 2
#define LOAD_CONST_STRING 3

#define MOV_NORMAL 0
#define MOV_T 1
#define MOV_MATV 2

#define JUMP_F 0
#define JUMP_R 1

#define MALLOC_MAT 0
#define MALLOC_LIST 1

typedef Object(*CFO0)();

typedef Object(*CFO1)(Object *);

typedef Object(*CFO2)(Object *, Object *);

typedef void(*CFV2)(Object *, Object *);

typedef Object(*CFO3)(Object *, Object *, Object *);

typedef void(*CFV4)(Object *, Object *, Object *, Object *);

typedef Object(*CFO4)(Object *, Object *, Object *, Object *);

typedef enum CFT {
    CFT_O0,
    CFT_O1,
    CFT_V2,
    CFT_O2,
    CFT_O3,
    CFT_V4,
    CFT_O4,
} CFT;

#define SIZE_OP 7
#define SIZE_K  2
#define SIZE_A  5
#define SIZE_B  9
#define SIZE_C  9
#define OFFSET_K (SIZE_OP)
#define OFFSET_A (SIZE_OP + SIZE_K)
#define OFFSET_B (SIZE_A + SIZE_OP + SIZE_K)
#define OFFSET_C (SIZE_B + SIZE_A + SIZE_OP+SIZE_K)

#define SET_ARG_K(i, r) (i = (i & 0xFFFFFE7F) | r << OFFSET_K)
#define SET_ARG_A(i, r) (i = (i & 0xFFFFC1FF) | r << OFFSET_A)
#define SET_ARG_B(i, r) (i = (i & 0xFF803FFF) | r << OFFSET_B)
#define SET_ARG_C(i, r) (i = (i & 0x007FFFFF) | r <<  OFFSET_C)
#define SET_ARG_Bx(i, r) (i = (i & 0x00003FFF) | r << OFFSET_B)

#define GET_OPCODE(i) (i & 0x7F)
#define GET_ARG_K(i) ((i & 0x180)>>OFFSET_K)
#define GET_ARG_A(i) ((i & 0x3E00) >> OFFSET_A)
#define GET_ARG_B(i) ((i & 0x7FC000) >> OFFSET_B)
#define GET_ARG_C(i) ((i & 0xFF800000) >> OFFSET_C)
#define GET_ARG_Bx(i) ((i & 0xFFFFC000) >> OFFSET_B)
typedef enum OPCODE {
    OP_END,//结束指令
    OP_MOVS,//取栈顶元素 STACK[TOP--]->R[a]
    OP_STORE,//存储操作 R[a]->M[bx] R[a]->STACK[call_state.STACK_START+bx]
    OP_LOAD,//加载内存到寄存器 k=0 M[bx]->R[a]
    OP_LOAD_CONST,//加载常量到寄存器
    // k=0 Int[bx]->R[a] k=1 Float[bx]->R[a] k=3 b->R[a] k=3 STR[bx]->R[a]
    OP_POP,//栈顶指针减小操作 TOP-- 附带GC操作
    OP_PUSH,//压栈操作 R[a]->STACK[++TOP]
    OP_ADD,//加法操作   只能运算寄存器内对象 STACK[++TOP]=R[b]+R[c] (以下相同)
    OP_SUB,//减法操作
    OP_MUL,//乘法操作
    OP_IMUL,//矩阵点乘操作
    OP_DIV,//除法操作
    OP_MOD,//取模操作
    OP_POW,//幂乘操作
    OP_NEG,//取负操作
    OP_LESS,//小于判断操作
    OP_LESSEQUAL,//小于等于判断操作
    OP_EQUAL,//相等判断操作
    OP_NOTEQUAL,//不相等判断操作
    OP_NOT,//非操作
    OP_AND,//与操作
    OP_OR,//或操作
    OP_CJUMP,//条件跳转 PC+=Bx PC-=Bx
    OP_JUMP,//无条件跳转 PC+=Bx PC-=Bx
    OP_MOV,//k=0 R[c]->R[b] k=3 R[2].mat[R[0]][R[1]]=R[4].value
    OP_CALL,// A represents Params Nums+inner var Nums Bx represents PC OFFSET,PC=bx
    OP_LEV,//函数返回操作 根据call_state进行跳转
    OP_PUSHP,//函数参数压栈操作 R[a]->STACK[++TOP]
    OP_POPP,//函数参数出栈操作 TOP--
    OP_CALLC,//C函数调用操作
    OP_MALLOC,//内存开辟操作 k=0 MALLOC_MAT k=1 MALLOC_LIST
    OP_INC,//基址寄存器自增操作
    OP_INDEX,//索引操作
    OP_LOAD_P,//加载Object指针操作
    OP_ASSIGN_P,//加载Object指针操作
    OP_MAT_INDEX,//矩阵寻址操作
    OP_MAT_ASSIGN//矩阵内部元素赋值操作
} OPCODE;
#endif //MATINTERPRETER_INSTRUCTION_H
